/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package technotheist.imgcog.net.convolve;

import technotheist.imgcog.net.FeedFwdNet;

/**
 *
 * @author Mitch
 */
public class ConvolutionNet extends FeedFwdNet {

    @Override
    protected ConvolutionNetRunner runner() {
        return (ConvolutionNetRunner) super.runner();
    }

    @Override
    protected void process() {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    protected abstract class ConvolutionNetRunner extends FeedFwdNetRunner {

        @Constant
        protected final int inputLenX, inputLenY, inputLenZ;
        @Constant
        protected final int outputLenX, outputLenY, outputLenZ;
        @Constant
        private final int[] layerLenX, layerLenY, layerLenZ, 
                layerKernSideLen, layerKernCount;

        public ConvolutionNetRunner(ConvolutionNetConfig config) {
            super(config);
            inputLenX = config.getInputLenX();
            inputLenY = config.getInputLenY();
            inputLenZ = config.getInputLenZ();
            outputLenX = config.getOutputLenX();
            outputLenY = config.getOutputLenY();
            outputLenZ = config.getOutputLenZ();
            layerLenX = new int[getLayerCount()];
            layerLenY = new int[getLayerCount()];
            layerLenZ = new int[getLayerCount()];
            layerKernSideLen = new int[getLayerCount()-1];
            layerKernCount = new int[getLayerCount()-1];
            //
            for (int i = 0; i < getLayerCount(); i++) {
                layerLenX[i] = config.getLayerLenX(i);
                layerLenY[i] = config.getLayerLenY(i);
                layerLenZ[i] = config.getLayerLenZ(i);
                if (i > 0) {
                    layerKernSideLen[i-1] = config.getLayerKernelSideLen(i - 1);
                    layerKernCount[i-1] = config.getLayerKernelCount(i-1);
                }
            }
        }
        
        
        
        //
        //

        @Override
        protected void runML(int mode, int layer) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        protected int getInputSrcNode(int layer, int node, int w) {
            int nx = nodeX(layer, node);
            int ny = nodeY(layer, node);
            int nz = nodeZ(layer, node);
            int kx = kernX(layer-1, w);
            int ky = kernY(layer-1, w);
            int kz = kernZ(layer-1, w);
            return index3D(nx + kx, ny + ky, nz + kz, layerLenY[layer-1], layerLenZ[layer-1]);
        }
        
        protected int kernX(int layer0, int w) {
            return x3D(w, layerKernSideLen[layer0], 
                    layerLenZ[layer0] * layerKernCount[0]);
        }
        
        protected int kernY(int layer0, int w) {
            return y3D(w, layerKernSideLen[layer0],
                    layerLenZ[layer0] * layerKernCount[0]);
        }
        
        protected int kernZ(int layer0, int w) {
            return z3D(w, layerLenZ[layer0] * layerKernCount[0])%layerLenZ[layer0];
        }
        
        protected int kernNum(int layer0, int w) {
            return z3D(w, layerLenZ[layer0] * layerKernCount[0])/layerLenZ[layer0];
        }
        
        protected int nodeX(int layer, int node) {
            return x3D(node, layerLenY[layer], layerLenZ[layer]);
        }
        
        protected int nodeY(int layer, int node) {
            return y3D(node, layerLenY[layer], layerLenZ[layer]);
        }
        
        protected int nodeZ(int layer, int node) {
            return z3D(node, layerLenZ[layer]);
        }
    }
}
